/**
 * JavaScript typeof 和 instanceof 演示代码
 * 可在浏览器控制台或Node.js环境中运行
 */

console.log('=== typeof 操作符演示 ===');

// 1. 基本数据类型检测
console.log('1. 基本数据类型检测:');
console.log('typeof 42:', typeof 42);                    // 'number'
console.log('typeof "hello":', typeof "hello");          // 'string'
console.log('typeof true:', typeof true);                // 'boolean'
console.log('typeof undefined:', typeof undefined);      // 'undefined'
console.log('typeof Symbol():', typeof Symbol());        // 'symbol'
// eslint-disable-next-line no-undef
if (typeof BigInt !== 'undefined') {
    // eslint-disable-next-line no-undef
    console.log('typeof BigInt(123):', typeof BigInt(123));  // 'bigint'
}

// 2. 特殊情况
console.log('\n2. 特殊情况:');
console.log('typeof null:', typeof null);                // 'object' (历史bug)
console.log('typeof []:', typeof []);                    // 'object'
console.log('typeof {}:', typeof {});                    // 'object'
console.log('typeof function(){}:', typeof function(){}); // 'function'

// 3. 变量存在性检查
console.log('\n3. 变量存在性检查:');
let testVar;
console.log('typeof testVar:', typeof testVar);          // 'undefined'
console.log('typeof notDeclaredVar:', typeof notDeclaredVar); // 'undefined'

console.log('\n=== instanceof 操作符演示 ===');

// 1. 构造函数实例检测
console.log('1. 构造函数实例检测:');
function Car(brand) {
    this.brand = brand;
}

const myCar = new Car('Toyota');
console.log('myCar instanceof Car:', myCar instanceof Car);           // true
console.log('myCar instanceof Object:', myCar instanceof Object);     // true

// 2. 内置对象检测
console.log('\n2. 内置对象检测:');
const arr = [1, 2, 3];
const obj = { name: 'test' };
const date = new Date();
const regex = /test/g;

console.log('arr instanceof Array:', arr instanceof Array);           // true
console.log('arr instanceof Object:', arr instanceof Object);         // true
console.log('obj instanceof Object:', obj instanceof Object);         // true
console.log('date instanceof Date:', date instanceof Date);           // true
console.log('regex instanceof RegExp:', regex instanceof RegExp);     // true

// 3. 基本类型与包装对象的区别
console.log('\n3. 基本类型与包装对象的区别:');
const str1 = 'hello';
const str2 = new String('hello');

console.log('typeof str1:', typeof str1);                            // 'string'
console.log('typeof str2:', typeof str2);                            // 'object'
console.log('str1 instanceof String:', str1 instanceof String);       // false
console.log('str2 instanceof String:', str2 instanceof String);       // true

console.log('\n=== 手动实现 instanceof ===');

// 手动实现 instanceof
function myInstanceof(left, right) {
    // 对于基础数据类型，直接返回false
    if (typeof left !== 'object' || left === null) return false;
    
    // 获取对象的原型
    let proto = Object.getPrototypeOf(left);
    
    while (proto !== null) {
        if (proto === right.prototype) return true;
        proto = Object.getPrototypeOf(proto);
    }
    return false;
}

// 测试自定义的 instanceof
console.log('myInstanceof(myCar, Car):', myInstanceof(myCar, Car));        // true
console.log('myInstanceof(arr, Array):', myInstanceof(arr, Array));        // true
console.log('myInstanceof(str1, String):', myInstanceof(str1, String));    // false
console.log('myInstanceof(str2, String):', myInstanceof(str2, String));    // true

console.log('\n=== 通用类型检测函数 ===');

// 通用类型检测函数
function getType(obj) {
    let type = typeof obj;
    if (type !== "object") {
        return type; // 基础类型直接返回
    }
    // 对于object类型，使用toString进行精确判断
    return Object.prototype.toString.call(obj).replace(/^\[object (\S+)\]$/, '$1');
}

// 测试通用类型检测函数
const testValues = [
    42,
    'hello',
    true,
    undefined,
    null,
    [],
    {},
    function() {},
    new Date(),
    /regex/,
    Symbol('test'),
    new Map(),
    new Set(),
    new WeakMap(),
    new WeakSet()
];

// 如果BigInt存在，添加到测试数组
// eslint-disable-next-line no-undef
if (typeof BigInt !== 'undefined') {
    // eslint-disable-next-line no-undef
    testValues.push(BigInt(123));
}

console.log('通用类型检测结果:');
testValues.forEach(value => {
    let valueStr;
    try {
        valueStr = JSON.stringify(value);
    } catch (e) {
        // 处理BigInt等不能被JSON序列化的值
        valueStr = String(value);
    }
    console.log(`getType(${valueStr}):`, getType(value));
});

console.log('\n=== 实际应用场景演示 ===');

// 1. 类型安全的数学运算
function safeAdd(a, b) {
    if (typeof a !== 'number' || typeof b !== 'number') {
        throw new Error('参数必须是数字类型');
    }
    return a + b;
}

console.log('1. 类型安全的数学运算:');
try {
    console.log('safeAdd(3, 4):', safeAdd(3, 4));      // 7
    console.log('safeAdd("3", 4):', safeAdd("3", 4));  // 抛出错误
} catch (error) {
    console.log('错误:', error.message);
}

// 2. 增强的数组检测
function isArray(value) {
    return Array.isArray ? Array.isArray(value) : value instanceof Array;
}

console.log('\n2. 数组检测:');
console.log('isArray([1, 2, 3]):', isArray([1, 2, 3]));  // true
console.log('isArray("hello"):', isArray("hello"));       // false
console.log('isArray({}):', isArray({}));                 // false

// 3. 判断纯对象
function isPlainObject(obj) {
    if (typeof obj !== 'object' || obj === null) {
        return false;
    }
    
    // 检查是否是纯对象（直接由Object构造函数创建）
    return Object.prototype.toString.call(obj) === '[object Object]';
}

console.log('\n3. 纯对象检测:');
console.log('isPlainObject({}):', isPlainObject({}));              // true
console.log('isPlainObject([]):', isPlainObject([]));              // false
console.log('isPlainObject(new Date()):', isPlainObject(new Date())); // false
console.log('isPlainObject(myCar):', isPlainObject(myCar));        // false

// 4. 深拷贝函数中的类型检测
function deepClone(obj) {
    if (typeof obj !== 'object' || obj === null) {
        return obj; // 基础类型直接返回
    }
    
    if (obj instanceof Date) {
        return new Date(obj.getTime());
    }
    
    if (obj instanceof Array) {
        return obj.map(item => deepClone(item));
    }
    
    if (obj instanceof Object) {
        const cloned = {};
        for (let key in obj) {
            if (Object.prototype.hasOwnProperty.call(obj, key)) {
                cloned[key] = deepClone(obj[key]);
            }
        }
        return cloned;
    }
    
    return obj;
}

console.log('\n4. 深拷贝演示:');
const original = {
    name: 'test',
    age: 25,
    hobbies: ['reading', 'coding'],
    createdAt: new Date()
};

const cloned = deepClone(original);
console.log('原对象:', original);
console.log('克隆对象:', cloned);
console.log('是否为同一对象:', original === cloned);          // false
console.log('数组是否为同一对象:', original.hobbies === cloned.hobbies); // false

console.log('\n=== 常见陷阱和注意事项 ===');

// 1. typeof null 的陷阱
console.log('1. typeof null 陷阱:');
console.log('typeof null:', typeof null);                  // 'object'
console.log('null === null:', null === null);              // true (正确的null检测)

// 2. 数组检测陷阱
console.log('\n2. 数组检测陷阱:');
console.log('typeof []:', typeof []);                      // 'object'
console.log('[] instanceof Array:', [] instanceof Array);   // true (正确的数组检测)

// 3. 函数检测
console.log('\n3. 函数检测:');
const func = function() {};
console.log('typeof func:', typeof func);                  // 'function'
console.log('func instanceof Function:', func instanceof Function); // true
console.log('func instanceof Object:', func instanceof Object);     // true

// 4. 跨iframe的instanceof问题演示（注释掉，因为需要DOM环境）
/*
console.log('\n4. 跨iframe问题（需要DOM环境）:');
// 在不同iframe中创建的数组，instanceof检测会失败
// const iframe = document.createElement('iframe');
// document.body.appendChild(iframe);
// const iframeArray = iframe.contentWindow.Array;
// const arr = new iframeArray();
// console.log('arr instanceof Array:', arr instanceof Array);     // false
// console.log('Array.isArray(arr):', Array.isArray(arr));        // true
*/

console.log('\n=== 面试题练习 ===');

// 面试题1: 如何判断一个变量是数组？
console.log('面试题1: 如何判断一个变量是数组？');
const testArray = [1, 2, 3];
console.log('方法1 - Array.isArray():', Array.isArray(testArray));
console.log('方法2 - instanceof:', testArray instanceof Array);
console.log('方法3 - toString:', Object.prototype.toString.call(testArray) === '[object Array]');

// 面试题2: 为什么 typeof null === 'object'？
console.log('\n面试题2: typeof null === "object" 的原因已在上面解释');

// 面试题3: 如何检测一个函数？
console.log('\n面试题3: 如何检测一个函数？');
const testFunc = () => {};
console.log('方法1 - typeof:', typeof testFunc === 'function');
console.log('方法2 - instanceof:', testFunc instanceof Function);
console.log('方法3 - toString:', Object.prototype.toString.call(testFunc) === '[object Function]');

// 面试题4: 基本类型和包装对象的区别
console.log('\n面试题4: 基本类型和包装对象的区别');
const primitiveString = 'hello';
const objectString = new String('hello');
console.log('primitiveString == objectString:', primitiveString == objectString);   // true
console.log('primitiveString === objectString:', primitiveString === objectString); // false
console.log('typeof primitiveString:', typeof primitiveString);                    // 'string'
console.log('typeof objectString:', typeof objectString);                          // 'object'

console.log('\n演示完成！'); 